﻿#include "GUICreateSEAShellSelectPicklDialog.h"
#include "ui_GUICreateSEAShellSelectPicklDialog.h"

#include "FITK_Kernel/FITKCore/FITKActionOperator.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"

#include "FITK_Component/FITKAcousticsModel/FITKAcousticsGeometryData.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysShellPlate.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysShellCurved.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEAFace.h"

// Pick
#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedDataProvider.h"
#include "PickDataProvider/PickedData.h"

#include <QButtonGroup>
#include <QRegExpValidator>
#include <QTabBar>
#include <QMessageBox>

namespace GUI {

    GUICreateSEAShellSelectPicklDialog::GUICreateSEAShellSelectPicklDialog(Core::FITKActionOperator* oper, QWidget* parent /*= nullptr*/) :
        GUIDialogBase(parent),
        _oper(oper),
        _ui(new Ui::GUICreateSEAShellSelectPicklDialog)
    {
        _ui->setupUi(this);
        // 设置对话框关闭时自动删除
        setAttribute(Qt::WA_DeleteOnClose);
        //去掉问号
        Qt::WindowFlags flags = windowFlags();
        flags &= ~Qt::WindowContextHelpButtonHint;
        setWindowFlags(flags);
        //去除tab的表头
        _ui->tabWidget_SelectPick->tabBar()->hide();
        _ui->lineEdit_NumLoop->setValidator(new QRegExpValidator(QRegExp("^[1-9]+([0-9])+$")));
        this->init();
        //获取拾取器，绑定拾取结束信号
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        //清除拾取对象所有的连接
        QObject::disconnect(pickProvider, SIGNAL(sig_pickedOver()), nullptr, nullptr);
        if (pickProvider)
        {
            connect(pickProvider, &GraphData::PickedDataProvider::sig_pickedOver, this, &GUICreateSEAShellSelectPicklDialog::pickFinished);
            connect(pickProvider, &GraphData::PickedDataProvider::sig_pickedData, this, &GUICreateSEAShellSelectPicklDialog::pickDataFinished);
        }
        //设置窗口自适应隐藏组件
        this->layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);
    }

    GUICreateSEAShellSelectPicklDialog::~GUICreateSEAShellSelectPicklDialog()
    {
        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
    }

    Acoustics::FITKAbstractSEASubSysShell * GUICreateSEAShellSelectPicklDialog::getShellData()
    {
        return _shellData;
    }

    void GUICreateSEAShellSelectPicklDialog::on_radioButton_BasicElem_clicked(bool checked)
    {
        if (!checked) return;
        _ui->tabWidget_SelectPick->setCurrentIndex(0);
        _ui->label_Picked->setEnabled(true);
        _ui->label_Picked->setText(QString("Picked (0)"));
        //初始化选项
        _ui->radioButton_Node->setChecked(true);
        this->on_radioButton_Node_clicked(true);
    }

    void GUICreateSEAShellSelectPicklDialog::on_radioButton_Group_clicked(bool checked)
    {
        if (!checked) return;
        _ui->tabWidget_SelectPick->setCurrentIndex(2);
        _ui->label_Picked->setEnabled(false);
        _ui->label_Picked->setText(QString("Picked (0)"));
    }

    void GUICreateSEAShellSelectPicklDialog::on_radioButton_Pid_clicked(bool checked)
    {
        if (!checked) return;
        _ui->tabWidget_SelectPick->setCurrentIndex(1);
        _ui->label_Picked->setEnabled(true);
        _ui->label_Picked->setText(QString("Picked (0)"));
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMByMeshProp;
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJMeshCell2D;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUICreateSEAShellSelectPicklDialog::on_radioButton_Node_clicked(bool checked)
    {
        if (!checked) return;
        _ui->label_Picked->setText(QString("Picked (0)"));
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJDiscNode;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
        if (_subSysType == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEADoublyCurvedShell)
        {
            //显示层数
            _ui->label_NumLoop->setVisible(true);
            _ui->lineEdit_NumLoop->setVisible(true);
        }
        else
        {
            //隐藏层数
            _ui->label_NumLoop->setVisible(false);
            _ui->lineEdit_NumLoop->setVisible(false);
        }
    }

    void GUICreateSEAShellSelectPicklDialog::on_radioButton_Geometry_clicked(bool checked)
    {
        if (!checked) return;
        _ui->label_Picked->setText(QString("Picked (0)"));
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJGeometryFace;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUICreateSEAShellSelectPicklDialog::on_radioButton_Mesh_clicked(bool checked)
    {
        if (!checked) return;
        _ui->label_Picked->setText(QString("Picked (0)"));
        //设置拾取方式
        GUI::GUIPickInfoStru pickInfo = GUI::GUIPickInfo::GetPickInfo();
        pickInfo._pickObjType = GUI::GUIPickInfo::PickObjType::POBJMeshCell2D;
        pickInfo._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
        GUI::GUIPickInfo::SetPickInfo(pickInfo);
    }

    void GUICreateSEAShellSelectPicklDialog::on_pushButton_Cancel_clicked()
    {
        this->reject();
    }

    void GUICreateSEAShellSelectPicklDialog::on_pushButton_OK_clicked()
    {
        //获取子系统管理器
        Acoustics::FITKAcousticsSEASubSysManager* subSysMgr = _SEAModel->getSEASubSysManager();
        if (!_oper || !subSysMgr) return;
        //清理数据
        if (_shellData)
            delete _shellData;
        _shellData = nullptr;
        //创建数据
        if (_subSysType == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEAFlatPlate)
            _shellData = new Acoustics::FITKSEASubSysPlateShell;
        else if (_subSysType == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEASinglyCurvedShell)
            _shellData = new Acoustics::FITKSEASubSysSinglyCurvedShell;
        else if (_subSysType == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEADoublyCurvedShell)
            _shellData = new Acoustics::FITKSEASubSysDoublyCurvedShell;
        if (!_shellData) return;
        //通过节点创建板
        if (_ui->radioButton_BasicElem->isChecked() && _ui->radioButton_Node->isChecked())
        {
            if (!this->createShellByNode())
                return;
        }
        //通过几何壳创建板
        else if (_ui->radioButton_BasicElem->isChecked() && _ui->radioButton_Geometry->isChecked())
        {
            if (!this->createShellByGeometry())
                return;
        }
        //通过面网格单元创建板
        else if (_ui->radioButton_BasicElem->isChecked() && _ui->radioButton_Mesh->isChecked())
        {
            if (!this->createShellByMesh())
                return;
        }
        //通过面网格属性创建板
        else if (_ui->radioButton_Pid->isChecked())
        {
            if (!this->createShellByPid())
                return;
        }
        //通过分组创建板
        else if (_ui->radioButton_Group->isChecked())
        {
            if (!this->createShellByGroup())
                return;
        }
        //更新几何属性
        _shellData->updateGeoProp();
        subSysMgr->appendDataObj(_shellData);
        _oper->setArgs("DataID", _shellData->getDataObjectID());

        this->accept();
    }

    bool GUICreateSEAShellSelectPicklDialog::createShellByNode()
    {
        if (!_shellData) return false;

        //设置双曲率的层数
        if (_subSysType == Acoustics::FITKAbstractSEASubSys::SEASubSysType::SEADoublyCurvedShell)
        {
            int numLoop = _ui->lineEdit_NumLoop->text().toInt();
            if (0 >= numLoop)
            {
                QMessageBox::warning(this, "", tr("Create Doubly Curved Plate err! The number of layers is not less than 0."), QMessageBox::Ok);
                return false;
            }
            Acoustics::FITKSEASubSysDoublyCurvedShell* doublyCurvedPlate = dynamic_cast<Acoustics::FITKSEASubSysDoublyCurvedShell*>(_shellData);
            if (!doublyCurvedPlate)return false;
            doublyCurvedPlate->setNumberOfRing(numLoop);
        }
        //获取三维可视化对象管理
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider)return false;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        //设置点数据
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> nodes;
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            GraphData::PickedDataType pickType = pickData->getPickedDataType();
            if (GraphData::PickedDataType::DiscNodePick == pickType)
                nodes.append(pickData->getPickedDiscNodes());
        }
        if (nodes.size() < 3)
        {
            QMessageBox::warning(this, "", tr("Create Plate err! The number of nodes is not less than 3."), QMessageBox::Ok);
            return false;
        }
        nodes[0]._type = Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNodeType::Start;
        
        _shellData->setNodes(nodes);
        //数据对象只有点的数据时，需要更新三角网格
        if (!_shellData->updateTriMesh())
        {
            QMessageBox::warning(this, "", tr("Create Plate err! Triangle patch error generated."), QMessageBox::Ok);
            return false;
        }
        return true;
    }

    bool GUICreateSEAShellSelectPicklDialog::createShellByGeometry()
    {
        if (!_shellData) return false;
        //获取三维可视化对象管理和几何数据
        Interface::FITKGeoCommandList *comList = FITKGLODATA->getGeometryData<Interface::FITKGeoCommandList>();
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider || !comList)return false;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        if (pickList.isEmpty()) {
            QMessageBox::warning(this, "", tr("Create Plate err! The geometry face data picked is 0."), QMessageBox::Ok);
            return false;
        }
        GraphData::PickedData* pickDataP = pickList.at(0);
        if (pickDataP == nullptr)return false;
        QList<int> pickedIds = pickDataP->getPickedIds();
        int DataObjId = pickDataP->getPickedDataObjId();
        if (pickedIds.isEmpty())
        {
            QMessageBox::warning(this, "", tr("Create Plate err! The geometry face data picked is 0."), QMessageBox::Ok);
            return false;
        }
        Interface::FITKAbsGeoCommand*comP = comList->getDataByID(DataObjId);
        if (!_shellData->updateTriMesh(comP, pickedIds.at(0)))
        {
            QMessageBox::warning(this, "", tr("Create Plate err! Triangle patch error generated."), QMessageBox::Ok);
            return false;
        }
        return true;
    }

    bool GUICreateSEAShellSelectPicklDialog::createShellByMesh()
    {
        if (!_shellData) return false;
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider)return false;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        //设置网格单元数据
        QHash<int, QList<int>> meshs;
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            GraphData::PickedDataType pickType = pickData->getPickedDataType();
            if (GraphData::PickedDataType::MeshCellPick == pickType)
            {
                //获取partID和单元Id
                int partID = pickData->getPickedDataObjId();
                QList<int> faceElemsID = pickData->getPickedIds();
                if (faceElemsID.isEmpty()) continue;
                meshs.insert(partID, faceElemsID);
            }
        }
        if (meshs.isEmpty())
        {
            QMessageBox::warning(this, "", tr("Create Plate err! The number of meshs is not less than 0."), QMessageBox::Ok);
            return false;
        }
        if (!_shellData->updateTriMesh(meshs))
        {
            QMessageBox::warning(this, "", tr("Create Plate err! Picked meshs err."), QMessageBox::Ok);
            return false;
        }
        Acoustics::FITKAbstractSEAFace* faceData = _shellData->getFaceObj();
        if (faceData)
            faceData->setFEFace(true);
        return true;
    }

    bool GUICreateSEAShellSelectPicklDialog::createShellByPid()
    {
        //获取几何数据和三维可视化对象管理
        Acoustics::FITKAcousticsGeometryData *comList = FITKGLODATA->getGeometryData<Acoustics::FITKAcousticsGeometryData>();
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider || !comList)return false;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        //设置网格单元数据
        QHash<int, QList<int>> meshs;
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            GraphData::PickedDataType pickType = pickData->getPickedDataType();
            if (GraphData::PickedDataType::MeshCellPick == pickType)
            {
                //获取partID和单元Id
                int partID = pickData->getPickedDataObjId();
                QList<int> faceElemsID = pickData->getPickedIds();
                if (faceElemsID.isEmpty()) continue;
                meshs.insert(partID, faceElemsID);
            }
        }
        if (meshs.isEmpty())
        {
            QMessageBox::warning(this, "", tr("Create Plate err! The number of meshs is not less than 0."), QMessageBox::Ok);
            return false;
        }
        if (!_shellData->updateTriMesh(meshs))
        {
            QMessageBox::warning(this, "", tr("Create Plate err! Picked meshs err."), QMessageBox::Ok);
            return false;
        }
        Acoustics::FITKAbstractSEAFace* faceData = _shellData->getFaceObj();
        if (faceData)
            faceData->setFEFace(true);
        return true;
    }

    bool GUICreateSEAShellSelectPicklDialog::createShellByGroup()
    {
        return true;
    }

    void GUICreateSEAShellSelectPicklDialog::reject()
    {
        //清除拾取模式和高亮
        GUI::GUIPickInfo::ClearPickInfo();
        this->QDialog::reject();
    }

    void GUICreateSEAShellSelectPicklDialog::init()
    {
        //获取子系统类型
        if (!_oper)return;
        _oper->argValue<int>("SEASubSysType", _subSysType);
        //初始化界面
        _ui->radioButton_BasicElem->setChecked(true);
        _ui->radioButton_Node->setChecked(true);
        this->on_radioButton_Node_clicked(true);
    }

    void GUICreateSEAShellSelectPicklDialog::pickFinished()
    {
        this->on_pushButton_OK_clicked();
    }

    void GUICreateSEAShellSelectPicklDialog::pickDataFinished()
    {
        if (!_oper) return;
        //获取三维可视化对象管理
        GraphData::PickedDataProvider* pickProvider = GraphData::PickedDataProvider::getInstance();
        if (!pickProvider)return;
        QList<int> objIDList;
        int size = 0;
        //获取拾取数据对象
        QList<GraphData::PickedData*> pickList = pickProvider->getPickedList();
        for (GraphData::PickedData* pickData : pickList)
        {
            if (!pickData) continue;
            objIDList.append(pickData->getPickedDataObjId());
            size = pickData->getPickedDiscNodes().size();
        }
        if (_ui->radioButton_Node->isChecked())
            _ui->label_Picked->setText(QString("Picked (%1)").arg(size));
        else if (_ui->radioButton_Geometry->isChecked())
            _ui->label_Picked->setText(QString("Picked (%1)").arg(objIDList.size()));
        else if (_ui->radioButton_Mesh->isChecked())
            _ui->label_Picked->setText(QString("Picked (%1)").arg(objIDList.size()));
    }
}
